﻿// --------------------------------
// <copyright file="CharacterSensor.cs" company="Faculty of Information Technology, Czech Technical University in Prague">
//     This document is shared by Microsoft Public License (MS-PL)
//     For further details please see http://msdn.microsoft.com/en-us/library/ff648068.aspx or license.txt.
// </copyright>
// <author>Vladislav Richter</author>

// <email>richtvl2@fit.cvut.cz</email>

// <date>9. 11. 2011 22:22:37</date>

// <summary>
//
// </summary>
// --------------------------------
using System;
using FarseerPhysics.Dynamics;
using FarseerPhysics.Dynamics.Contacts;
using FarseerPhysics.Factories;
using FITClub.Episode1.Components.CharacterActions;
using FITClub.Episode1.Controller;
using FITClub.Episode1.Primitives3D;
using Microsoft.Xna.Framework;

namespace FITClub.Episode1.Components.Physics
{
    /// <summary>
    /// This class represents avatar's fists and is reposnsible for attack execution
    /// </summary>
    public class CharacterSensor
    {
        #region FIELDS

        public Body Sensor;
        /// <summary>
        /// Bone of avatar's model this sensor is attached to
        /// </summary>
        public int BoneIndex;
        public PlayableCharacter Character;
        public CharacterPhysics Physx;
        public float Radius = 0.05f;
        public Matrix World;
        public SpherePrimitive spherePrimitive;

        #endregion FIELDS

        #region METHODS

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="physx">Physics world</param>
        /// <param name="bone">Bone this sensor is attached to</param>
        public CharacterSensor(CharacterPhysics physx, String bone)
        {
            Physx = physx;
            Character = Physx.Player;
            BoneIndex = Character.AnimPlayer.AnimData.skinningData.BoneIndices[bone];
            Sensor = BodyFactory.CreateCircle(Character.game.PhysicsWorld, Radius, 1, "fist");
            Sensor.IsSensor = true;
            Sensor.OnCollision += SensorOnCollision;
            Sensor.OnSeparation += SensorOnSeparation;
            Sensor.IgnoreCollisionWith(Physx.Torso);
            Sensor.IgnoreCollisionWith(Physx.Motor.MotorWheel);
            spherePrimitive = new SpherePrimitive(Character.GraphicsDevice, 0.7f, 12);
            Sensor.Enabled = false;
        }

        public void Update()
        {
            World = Character.AnimPlayer.GetWorldTransforms()[BoneIndex] * Character.CharacterMatrix;
            Vector3 pos = World.Translation;
            Sensor.SetTransform(new Vector2(pos.X, pos.Y), 0);
        }

        /// <summary>
        /// Debug only!
        /// </summary>
        public void Draw()
        {
            spherePrimitive.Draw(World, Character.game.ViewMatrix, Character.game.ProjectionMatrix, Color.Red);
        }

        /// <summary>
        /// If this sensor dectects collision, it means that it is active and it is active only during attack, which means that this fist hit something
        /// - if this something is actually someone knock him down or push him a little if he is in block
        /// </summary>
        /// <param name="f1"></param>
        /// <param name="f2"></param>
        /// <param name="contact"></param>
        /// <returns></returns>
        public bool SensorOnCollision(Fixture f1, Fixture f2, Contact contact)
        {
            //Console.WriteLine("Sensor collision with "+(f2.Body.UserData !=null?pch2.Name:"null"));
            PlayableCharacter pch2 = f2.Body.UserData as PlayableCharacter;
            if (pch2 != null)
            {
                if (pch2.Actions.Status.Movement == MovementStatus.Duck
                    && pch2.Actions.Status.Flying == false
                    && f2.UserData != null
                    && Character.Actions.Status.Movement != MovementStatus.Duck
                    && Character.Actions.Status.Movement != MovementStatus.Jump
                    && Character.Actions.Status.Flying == false
                    && f2.UserData.ToString() == "head")
                {
                    return false;
                }
                this.Sensor.Enabled = false;
                if (pch2.Actions.Status.Blocking
                    && pch2.Direction == -Character.Direction
                    && (
                        (Character.Actions.Status.Movement != MovementStatus.Duck && pch2.Actions.Status.Movement != MovementStatus.Duck)
                        || (Character.Actions.Status.Movement == MovementStatus.Duck && pch2.Actions.Status.Movement == MovementStatus.Duck)
                        ))
                {
                    if (Character.Actions.Status.PowerUpEffect == Levels.PowerUpType.SuperPunch)
                    {
                        f2.Body.FixedRotation = false;
                        this.Character.CharPhysx.Torso.ResetDynamics();
                        pch2.CharPhysx.Motor.MotorWheel.FixedRotation = false;
                        pch2.Actions.Status.Stunned = true;
                        pch2.Actions.Status.ResetStunnedTime();
                        pch2.LastContactWith = this.Character;
                        f2.Body.ApplyLinearImpulse(new Vector2(Character.Direction * -0.2f, 0.15f), contact.Manifold.Points[0].LocalPoint);
                        pch2.contacts.Clear();
                        pch2.CharPhysx.RFist.Sensor.Enabled = false;
                        pch2.CharPhysx.LFist.Sensor.Enabled = false;
                        pch2.CharPhysx.MotorStop();
                        pch2.CharPhysx.StandUp();
                        pch2.Actions.Status.Movement = MovementStatus.Still;
                        pch2.AnimPlayer.StopAllTakes();
                        pch2.AnimPlayer.StartTake("Get_Hit_Bottom");
                        Character.game.SoundPlayer.PlaySoundEffect("Punch", Character.CharPhysx.GetPosition());
                    }
                    else
                    {
                        f2.Body.ApplyLinearImpulse(new Vector2(Character.Direction * -0.1f, 0.15f), contact.Manifold.Points[0].LocalPoint);
                    }
                }
                else
                {
                    f2.Body.FixedRotation = false;
                    this.Character.CharPhysx.Torso.ResetDynamics();
                    pch2.CharPhysx.Motor.MotorWheel.FixedRotation = false;
                    pch2.Actions.Status.Stunned = true;
                    pch2.Actions.Status.ResetStunnedTime();
                    pch2.LastContactWith = this.Character;
                    if (Character.Actions.Status.PowerUpEffect == Levels.PowerUpType.SuperPunch)
                    {
                        f2.Body.ApplyLinearImpulse(new Vector2(Character.Direction * -0.3f, 0.3f), contact.Manifold.Points[0].LocalPoint);
                    }
                    else
                    {
                        f2.Body.ApplyLinearImpulse(new Vector2(Character.Direction * -0.2f, 0.3f), contact.Manifold.Points[0].LocalPoint);
                    }
                    pch2.contacts.Clear();
                    pch2.Actions.Status.Movement = MovementStatus.Still;
                    pch2.CharPhysx.RFist.Sensor.Enabled = false;
                    pch2.CharPhysx.LFist.Sensor.Enabled = false;
                    pch2.CharPhysx.MotorStop();
                    pch2.CharPhysx.StandUp();
                    pch2.AnimPlayer.StopAllTakes();
                    pch2.AnimPlayer.StartTake("Get_Hit_Bottom");
                    Character.game.SoundPlayer.PlaySoundEffect("Punch", Character.CharPhysx.GetPosition());
                }
            }

            Character.FireGavePunch(pch2);
            pch2.FireGotPunch(Character);

            return true;
        }

        public void SensorOnSeparation(Fixture f1, Fixture f2)
        {
        }

        #endregion METHODS
    }
}